<?php
abstract class Kbs_Model_Business_Abstract
{
    /**
     * Must be assigned within instance
     */
    protected $_mapperClassName = '';

    /**
     * Mapper instance
     */
    protected $_mapper = null;

    /**
     * Table row for this instance
     *
     * @var Zend_Db_Table_Row
     */
    protected $_tableRow = null;

    /**
     * Get table row
     */
    public function getTableRow()
    {
        return $this->_tableRow;
    }

    public function setTableRow(Zend_Db_Table_Row $row)
    {
        $this->_tableRow = $row;
        return $this;
    }

    /**
     * Get ids
     * Need to applied within instance
     */
    abstract public function getId();
    abstract public function setId($id);

    /**
     * Constructor
     * 
     * @param  array|null $data
     * @return void
     */
    public function __construct(array $data = null)
    {
        if (!empty($data)) {
            $this->setOptions($data);            
        }
        return $this;
    }

    /**
     * Overloading: allow property access
     * 
     * @param  string $name 
     * @param  mixed $value 
     * @return void
     */
    public function __set($name, $value)
    {
        $method = 'set' . ucfirst($name);
        if ('mapper' == $name || 'mapperClassName' == $name || !method_exists($this, $method)) {
            throw new Exception(get_class($this) . ' Invalid property specified : ' . $name);
        }
        $this->$method($value);
    }

    /**
     * Overloading: allow property access
     * 
     * @param  string $name 
     * @return mixed
     */
    public function __get($name)
    {
        $method = 'get' . ucfirst($name);
        if ('mapper' == $name || 'mapperClassName' == $name || !method_exists($this, $method)) {
            throw new Exception(get_class($this) . ' Invalid property specified : ' . $name);
        }
        return $this->$method();
    }

    /**
     * Return object as array
     * 
     * @return array|false
     */
    public function toArray()
    {
        return $this->getMapper()->toArray($this);
    }

    /**
     * Set data mapper
     * 
     * @param  mixed $mapper 
     * @return Kbs_Model_Mapper_Abstract|string
     */
    public function setMapper($mapper)
    {
        if (is_object($mapper) and $mapper instanceof Kbs_Model_Mapper_Abstract) {
            $this->_mapper = $mapper;
        } elseif (is_string($mapper) and class_exists($mapper)) {
            $this->_mapper = new $mapper();
        } else {
            throw new Exception('Data mapper should be instance of '
                               .'Kbs_Model_Mapper_Abstract or class name of '
                               .'Kbs_Model_Mapper_Abstract !');
        }
        return $this;
    }

    /**
     * Get data mapper
     *
     * Lazy loads Kbs_Model_Mapper_Abstract instance if no mapper registered.
     * 
     * @return Kbs_Model_Mapper_Abstract
     */
    public function getMapper()
    {
        if (null === $this->_mapper) {
            if (empty($this->_mapperClassName) or !class_exists($this->_mapperClassName)) {
                throw new Exception('Mapper class name must be assigned within ' . get_class($this) . ' !');
            }
            $this->setMapper($this->_mapperClassName);
        }
        return $this->_mapper;
    }

    /**
     * Find an entry
     *
     * Resets entry state if matching id found.
     * 
     * @param  int $id 
     * @return Kbs_Model_Business_Abstract|false
     */
    public function find($id)
    {
        $result = $this->getMapper()->find($id, $this);
        if ($result) {
            return $this;
        }
        return false;
    }

    /**
     * Fetch all entries
     * 
     * @return array|false
     */
    public function fetchAll($where = null)
    {
        return $this->getMapper()->fetchAll(get_class($this), $where = null);
    }

    /**
     * Save the current entry
     * 
     * @return void
     */
    public function save()
    {
        return $this->getMapper()->save($this);
    }

    /**
     * Delete the record
     *
     * 
     */
    public function delete()
    {
        return $this->getMapper()->delete($this);
    }

    /**
     * Overloading: implements accessible methods 
     *
     * @param string $name
     * @param array $arguments
     * @return mixed
     */
    public function __call($function, $arguments) {
        array_push($arguments, get_class($this));
        return $this->getMapper()->__call($function, $arguments);
    }

}